package com.haohan.cloud.scm.opc.core.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.haohan.cloud.scm.api.aftersales.entity.ReturnOrder;
import com.haohan.cloud.scm.api.aftersales.req.ReturnOrderReq;
import com.haohan.cloud.scm.api.constant.enums.aftersales.ReturnStatusEnum;
import com.haohan.cloud.scm.api.constant.enums.common.ReviewStatusEnum;
import com.haohan.cloud.scm.api.constant.enums.opc.BuySeqEnum;
import com.haohan.cloud.scm.api.constant.enums.opc.YesNoEnum;
import com.haohan.cloud.scm.api.constant.enums.saleb.BillTypeEnum;
import com.haohan.cloud.scm.api.constant.enums.saleb.BuyOrderStatusEnum;
import com.haohan.cloud.scm.api.crm.dto.CustomerMerchantDTO;
import com.haohan.cloud.scm.api.crm.entity.SalesOrder;
import com.haohan.cloud.scm.api.crm.req.SalesOrderReq;
import com.haohan.cloud.scm.api.opc.entity.BuyerPayment;
import com.haohan.cloud.scm.api.opc.req.payment.CountReceivableBillReq;
import com.haohan.cloud.scm.api.opc.req.payment.PaymentDetailReq;
import com.haohan.cloud.scm.api.opc.resp.BuyerPaymentResp;
import com.haohan.cloud.scm.api.saleb.entity.BuyOrder;
import com.haohan.cloud.scm.api.saleb.entity.Buyer;
import com.haohan.cloud.scm.api.saleb.req.BuyOrderDetailReq;
import com.haohan.cloud.scm.api.saleb.req.BuyOrderReq;
import com.haohan.cloud.scm.api.saleb.req.BuyerReq;
import com.haohan.cloud.scm.api.supply.entity.Supplier;
import com.haohan.cloud.scm.api.supply.req.SupplierReq;
import com.haohan.cloud.scm.common.tools.exception.EmptyDataException;
import com.haohan.cloud.scm.common.tools.exception.ErrorDataException;
import com.haohan.cloud.scm.opc.core.IBuyerPaymentCoreService;
import com.haohan.cloud.scm.opc.service.BuyerPaymentService;
import com.haohan.cloud.scm.opc.utils.ScmOpcUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @author dy
 * @date 2019/7/3
 */
@Slf4j
@Service
@AllArgsConstructor
public class BuyerPaymentCoreServiceImpl implements IBuyerPaymentCoreService {

    private final BuyerPaymentService buyerPaymentService;
    private final ScmOpcUtils scmOpcUtils;

    /**
     * 分页查询 结果带联查数据  未使用
     *
     * @param page
     * @param buyerPayment
     * @return
     */
    @Override
    public IPage fetchPage(Page page, BuyerPayment buyerPayment) {
        IPage resp = buyerPaymentService.page(page, Wrappers.query(buyerPayment).orderByDesc("buyer_payment_id"));
        List<BuyerPaymentResp> list = new ArrayList<>();
        BuyerPaymentResp buyerPaymentResp;
        if (CollUtil.isNotEmpty(resp.getRecords())) {
            for (Object b : resp.getRecords()) {
                buyerPaymentResp = BeanUtil.toBean(b, BuyerPaymentResp.class);
                if (buyerPaymentResp.getBillType() == null) {
                    continue;
                }
                // 客户名称 /商家名称 设置
                String customerName = "";
                String merchantName = "";
                switch (buyerPaymentResp.getBillType()) {
                    case order:
                        // 订单应收
                        BuyerReq buyerReq = new BuyerReq();
                        buyerReq.setId(buyerPaymentResp.getBuyerId());
                        Buyer buyer = scmOpcUtils.queryBuyer(buyerReq);
                        if (null != buyer) {
                            customerName = buyer.getBuyerName();
                            merchantName = buyer.getMerchantName();
                        }
                        break;
                    case offerBack:
                        //  采购退款应收
                        SupplierReq req = new SupplierReq();
                        req.setId(buyerPaymentResp.getBuyerId());
                        Supplier supplier = scmOpcUtils.querySupplier(req);
                        if (null != supplier) {
                            customerName = supplier.getSupplierName();
                            merchantName = supplier.getMerchantName();
                        }
                        break;
                    default:
                }
                buyerPaymentResp.setCustomerName(customerName);
                buyerPaymentResp.setMerchantName(merchantName);
                // todo 制单人
                list.add(buyerPaymentResp);
            }
        }
        resp.setRecords(list);
        return resp;
    }

    /**
     * 创建应收账单
     * 根据 应付来源订单编号:receivableSn/账单类型:billType 去查对应订单获取金额
     *
     * @param buyerPayment 必需:pmId/receivableSn/billType
     * @return 失败时返回null
     */
    @Override
    public BuyerPayment createReceivable(BuyerPayment buyerPayment) {
        BuyerPayment result;
        String pmId = buyerPayment.getPmId();
        String receivableSn = buyerPayment.getReceivableSn();
        // 是否已创建应收账单
        QueryWrapper<BuyerPayment> query = new QueryWrapper<>();
        query.lambda()
                .eq(BuyerPayment::getPmId, pmId)
                .and(q -> q.eq(BuyerPayment::getReceivableSn, receivableSn)
                        .or().eq(BuyerPayment::getBuyId, receivableSn));
        result = buyerPaymentService.getOne(query);
        if (null != result) {
            return result;
        }
        switch (buyerPayment.getBillType()) {
            case order:
                // 订单应收 订单未取消
                result = initReceivableByBuyOrder(pmId, receivableSn);
                break;
            case offerBack:
                //  采购退款应收
                result = initReceivableByReturnOrder(pmId, receivableSn);
                break;
            case sales:
                // 销售订单应收
                result = initReceivableBySalesOrder(pmId, receivableSn);
                break;
            default:
                result = null;
        }
        // 创建
        if (null != result) {
            buyerPaymentService.save(result);
        }
        return result;
    }

    /**
     * 根据 销售订单 初始创建 应收账单
     *
     * @param receivableSn
     * @return
     */
    private BuyerPayment initReceivableBySalesOrder(String pmId, String receivableSn) {
        // 销售订单
        SalesOrderReq req = new SalesOrderReq();
        req.setSalesOrderSn(receivableSn);
        SalesOrder salesOrder = scmOpcUtils.querySalesOrder(req);
        if (null == salesOrder) {
            return null;
        }
        // 客户商家获取
        CustomerMerchantDTO customer = scmOpcUtils.fetchCustomerMerchant(salesOrder.getCustomerSn());
        // 账单初始设置
        BuyerPayment result = new BuyerPayment();
        result.setPmId(pmId);
        result.setReceivableSn(receivableSn);
        result.setBillType(BillTypeEnum.sales);
        result.setBuyerPayment(salesOrder.getTotalAmount());
        result.setStatus(YesNoEnum.no);
        // 订单成交日期 =>  交货日期
        result.setBuyDate(salesOrder.getDeliveryDate());
        result.setReviewStatus(ReviewStatusEnum.wait);
        result.setBuyerId(customer.getCustomerId());
        result.setCustomerName(customer.getCustomerName());
        result.setMerchantId(customer.getMerchantId());
        result.setMerchantName(customer.getMerchantName());
        return result;
    }

    /**
     * 根据 退货单returnOrder 初始创建 应收账单
     *
     * @param pmId
     * @param receivableSn
     * @return
     */
    private BuyerPayment initReceivableByReturnOrder(String pmId, String receivableSn) {
        // 采购退货应收
        ReturnOrderReq req = new ReturnOrderReq();
        req.setPmId(pmId);
        req.setReturnSn(receivableSn);
        ReturnOrder returnOrder = scmOpcUtils.fetchRefund(req);
        if (null == returnOrder) {
            return null;
        }
        SupplierReq supplierReq = new SupplierReq();
        supplierReq.setId(returnOrder.getReturnCustomerId());
        supplierReq.setPmId(pmId);
        Supplier supplier = scmOpcUtils.querySupplier(supplierReq);
        if (null == supplier) {
            return null;
        }
        // 账单初始设置
        BuyerPayment result = new BuyerPayment();
        result.setPmId(pmId);
        result.setReceivableSn(receivableSn);
        result.setBillType(BillTypeEnum.offerBack);
        result.setBuyerPayment(returnOrder.getTotalAmount());
        result.setStatus(YesNoEnum.no);
        // 订单成交日期 =>  退货单申请日期
        LocalDateTime applyTime = returnOrder.getApplyTime();
        if (null == applyTime) {
            applyTime = returnOrder.getCreateDate();
        }
        result.setBuyDate(applyTime.toLocalDate());
        result.setReviewStatus(ReviewStatusEnum.wait);
        result.setBuyerId(supplier.getId());
        result.setCustomerName(supplier.getSupplierName());
        result.setMerchantId(supplier.getMerchantId());
        result.setMerchantName(supplier.getMerchantName());
        return result;
    }

    /**
     * 根据 客户订单buyOrder 初始创建 应收账单
     *
     * @param pmId
     * @param receivableSn
     * @return
     */
    private BuyerPayment initReceivableByBuyOrder(String pmId, String receivableSn) {
        // 订单应收 订单未取消
//        QueryWrapper<BuyOrder> queryWrapper = new QueryWrapper<>();
//        queryWrapper.lambda()
//                .eq(BuyOrder::getPmId, pmId)
//                .ne(BuyOrder::getStatus, BuyOrderStatusEnum.cancel)
//                .eq(BuyOrder::getBuyId, receivableSn);
//        BuyOrder buyOrder = buyOrderService.getOne(queryWrapper);
        BuyOrderReq req = new BuyOrderReq();
        req.setPmId(pmId);
        req.setBuyId(receivableSn);
        BuyOrder buyOrder = scmOpcUtils.queryBuyOrder(req);
        if (null == buyOrder || buyOrder.getStatus() == BuyOrderStatusEnum.cancel) {
            return null;
        }
        BuyerReq buyerReq = new BuyerReq();
        buyerReq.setPmId(pmId);
        buyerReq.setId(buyOrder.getBuyerId());
        Buyer buyer = scmOpcUtils.queryBuyer(buyerReq);
        if (null == buyer) {
            return null;
        }
        // 账单初始设置
        BuyerPayment result = new BuyerPayment();
        result.setPmId(pmId);
        result.setReceivableSn(receivableSn);
        result.setBillType(BillTypeEnum.order);
        result.setBuyerPayment(buyOrder.getGenPrice());
        result.setStatus(YesNoEnum.no);
        result.setBuyDate(buyOrder.getDeliveryTime());
        result.setReviewStatus(ReviewStatusEnum.wait);
        result.setBuyerId(buyer.getId());
        result.setCustomerName(buyer.getBuyerName());
        result.setMerchantId(buyer.getMerchantId());
        result.setMerchantName(buyer.getMerchantName());
        return result;
    }

    /**
     * 查询应收账单 是否通过审核  带商家名称
     *
     * @param buyerPayment 必需 pmId / BuyerPaymentId
     * @return 不为确认状态时 返回null
     */
    @Override
    public BuyerPayment checkPayment(BuyerPayment buyerPayment) {
        String pmId = buyerPayment.getPmId();
        String paymentSn = buyerPayment.getBuyerPaymentId();
        QueryWrapper<BuyerPayment> query = new QueryWrapper<>();
        // 通过审核
        query.lambda()
                .eq(BuyerPayment::getPmId, pmId)
                .eq(BuyerPayment::getReviewStatus, ReviewStatusEnum.success)
                .eq(BuyerPayment::getBuyerPaymentId, paymentSn);
        BuyerPayment payment = buyerPaymentService.getOne(query);
        if (null == payment || null == payment.getBillType()) {
            return null;
        }
        return payment;
    }

    /**
     * 批量创建应收账单  都是 订单应收
     * 根据 配送日期/批次
     *
     * @param buyOrder pmId/ 配送日期/批次
     * @return 创建的订单号 未创建返回null
     */
    @Override
    public String createReceivableBatch(BuyOrder buyOrder) {
        String pmId = buyOrder.getPmId();
        LocalDate deliveryDate = buyOrder.getDeliveryTime();
        BuySeqEnum buySeq = buyOrder.getBuySeq();

        // 订单应收  订单未取消
//        QueryWrapper<BuyOrder> queryWrapper = new QueryWrapper<>();
//        queryWrapper.lambda()
//                .eq(BuyOrder::getPmId, pmId)
//                .ne(BuyOrder::getStatus, BuyOrderStatusEnum.cancel)
//                .eq(BuyOrder::getDeliveryTime, deliveryDate)
//                .eq(BuyOrder::getBuySeq, buySeq);
        BuyOrderReq buyOrderReq = new BuyOrderReq();
        buyOrderReq.setPmId(pmId);
        buyOrderReq.setDeliveryTime(deliveryDate);
        buyOrderReq.setBuySeq(buySeq);
        List list = scmOpcUtils.queryBuyOrderList(buyOrderReq);
        if (CollUtil.isEmpty(list)) {
            throw new ErrorDataException("所选时间批次找不到订单");
        }
        List<BuyOrder> buyOrderList = new ArrayList<>(list.size());
        BuyOrder temp;
        for (Object obj : list) {
            temp = BeanUtil.toBean(obj, BuyOrder.class);
            if (temp.getStatus() == BuyOrderStatusEnum.cancel) {
                continue;
            }
            buyOrderList.add(temp);
        }
        if (CollUtil.isEmpty(list)) {
            throw new ErrorDataException("所选时间批次找不到订单");
        }
        BuyerPayment buyerPayment = new BuyerPayment();
        buyerPayment.setPmId(pmId);
        buyerPayment.setBillType(BillTypeEnum.order);
        // 创建应收账单
        BuyerPayment create;
        int num = 0;
        for (BuyOrder b : buyOrderList) {
            buyerPayment.setReceivableSn(b.getBuyId());
            create = createReceivable(buyerPayment);
            if (null != create) {
                num++;
            }
        }
        if (num > 0) {
            return "所选时间批次账单数为" + num;
        }
        return null;
    }

    /**
     * 查询应收账单是否可审核 对应订单需为确认状态
     *
     * @param pmId
     * @param buyerPaymentId
     * @return 账单更新金额
     */
    @Override
    public BuyerPayment checkReceivable(String pmId, String buyerPaymentId) {
        BuyerPayment result;
        QueryWrapper<BuyerPayment> query = new QueryWrapper<>();
        query.lambda()
                .eq(BuyerPayment::getPmId, pmId)
                .eq(BuyerPayment::getBuyerPaymentId, buyerPaymentId);
        BuyerPayment payment = buyerPaymentService.getOne(query);
        if (null == payment || null == payment.getBillType()) {
            return null;
        }
        // 不同类型处理
        switch (payment.getBillType()) {
            case order:
                // 订单应收
                result = checkReceivableByBuyOrder(pmId, payment);
                break;
            case offerBack:
                // 采购退款应收
                result = checkReceivableByReturnOrder(pmId, payment);
                break;
            case sales:
                // 销售应收
                result = checkReceivableBySalesOrder(payment);
                break;
            default:
                result = null;
        }
        return result;
    }


    /**
     * 更新总金额
     *
     * @param totalAmount
     * @param payment
     * @return
     */
    private BuyerPayment updatePaymentAmount(BigDecimal totalAmount, BuyerPayment payment) {
        if (null == totalAmount) {
            return null;
        }
        // 不同时更新
        if (totalAmount.compareTo(payment.getBuyerPayment()) != 0) {
            BuyerPayment update = new BuyerPayment();
            update.setId(payment.getId());
            update.setBuyerPayment(totalAmount);
            buyerPaymentService.updateById(update);
            payment.setBuyerPayment(totalAmount);
        }
        return payment;
    }

    /**
     * 销售应收账单
     *
     * @param payment
     * @return
     */
    private BuyerPayment checkReceivableBySalesOrder(BuyerPayment payment) {
        //  需已通过审核
        SalesOrderReq req = new SalesOrderReq();
        req.setSalesOrderSn(payment.getReceivableSn());
        req.setReviewStatus(ReviewStatusEnum.success);
        SalesOrder salesOrder = scmOpcUtils.querySalesOrder(req);
        if (null == salesOrder) {
            return null;
        }
        // 更新总金额
        return updatePaymentAmount(salesOrder.getTotalAmount(), payment);
    }

    /**
     * 订单应收账单 是否为确认状态,及对应金额
     *
     * @param pmId
     * @param payment
     * @return
     */
    private BuyerPayment checkReceivableByBuyOrder(String pmId, BuyerPayment payment) {
        // 兼容原系统
        String buyId = payment.getReceivableSn();
        buyId = (StrUtil.isEmpty(buyId)) ? payment.getBuyId() : buyId;
        // 订单应收  订单成交
        BuyOrderReq req = new BuyOrderReq();
        req.setPmId(pmId);
        req.setBuyId(buyId);
        req.setStatus(BuyOrderStatusEnum.success);
        BuyOrder buyOrder = scmOpcUtils.queryBuyOrder(req);
        if (null == buyOrder) {
            return null;
        }
        // 更新总金额
        return updatePaymentAmount(buyOrder.getTotalPrice(), payment);
    }

    /**
     * 退货应收账单 是否为确认状态,及对应金额
     *
     * @param pmId
     * @param payment
     * @return
     */
    private BuyerPayment checkReceivableByReturnOrder(String pmId, BuyerPayment payment) {
        // 采购退货应收  状态:已退货
        ReturnOrderReq req = new ReturnOrderReq();
        req.setPmId(pmId);
        req.setReturnStatus(ReturnStatusEnum.goods_back);
        req.setReturnSn(payment.getReceivableSn());
        ReturnOrder returnOrder = scmOpcUtils.queryReturnOrder(req);
        if (null == returnOrder) {
            return null;
        }
        // 更新总金额
        return updatePaymentAmount(returnOrder.getTotalAmount(), payment);
    }

    /**
     * 审核应收账单
     *
     * @param buyerPayment 必需 pmId / reviewStatus / buyerPayment/ buyerPaymentId 可选: remarks
     * @return
     */
    @Override
    public boolean reviewPayment(BuyerPayment buyerPayment) {
        QueryWrapper<BuyerPayment> query = new QueryWrapper<>();
        query.lambda()
                .eq(BuyerPayment::getPmId, buyerPayment.getPmId())
                .eq(BuyerPayment::getBuyerPaymentId, buyerPayment.getBuyerPaymentId());
        BuyerPayment origin = buyerPaymentService.getOne(query);
        if (null == origin) {
            return false;
        }
        buyerPayment.setId(origin.getId());
        // 审核通过时 修改金额
        if (buyerPayment.getReviewStatus() != ReviewStatusEnum.success) {
            buyerPayment.setBuyerPayment(null);
        }
        return buyerPaymentService.updateById(buyerPayment);
    }

    /**
     * 查询账单详情  todo 修改后废弃
     *
     * @param req
     * @return
     */
    @Override
    public List queryPaymentDetail(PaymentDetailReq req) {
        if (req.getReceivableSn().indexOf("RA") == -1) {
            BuyOrderReq orderReq = new BuyOrderReq();
            orderReq.setPmId(req.getPmId());
            orderReq.setBuyId(req.getReceivableSn());
            BuyOrder order = scmOpcUtils.queryBuyOrder(orderReq);
            if (ObjectUtil.isNull(order)) {
                throw new EmptyDataException();
            }
            BuyOrderDetailReq detailReq = new BuyOrderDetailReq();
            detailReq.setPmId(req.getPmId());
            detailReq.setBuyId(req.getReceivableSn());
            List list = scmOpcUtils.queryBuyOrderDetailList(detailReq);
            if (list.isEmpty()) {
                throw new EmptyDataException();
            }
            return list;
        }
        BuyOrderDetailReq buyOrderDetailReq = new BuyOrderDetailReq();
        buyOrderDetailReq.setPmId(req.getPmId());
        buyOrderDetailReq.setBuyId(req.getReceivableSn());
        return scmOpcUtils.queryBuyOrderDetailList(buyOrderDetailReq);
    }

    /**
     * 查询到期的应收账单数
     *
     * @param req
     * @return
     */
    @Override
    public Integer countReceivableBill(CountReceivableBillReq req) {
        BuyerReq buyerReq = new BuyerReq();
        buyerReq.setPmId(req.getPmId());
        buyerReq.setId(req.getBuyerId());
        Buyer buyer = scmOpcUtils.queryBuyer(buyerReq);
        if (null == buyer) {
            throw new ErrorDataException("采购商有误");
        }
        return buyerPaymentService.countBill(req.getEndDate(), req.getBuyerId(), req.getType());
    }
}
